package org.jackysoft.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.jackysoft.entity.Department;
import org.jackysoft.entity.DepartmentType;
import org.jackysoft.entity.User;
import org.jackysoft.google.collection.DepartmentZtreeFunction;
import org.jackysoft.google.collection.UserZtreeFunction;
import org.jackysoft.google.collection.ZTreeNode;
import org.jackysoft.service.AbstractIdentifiedService;
import org.jackysoft.service.DepartmentService;
import org.jackysoft.service.UserService;
import org.jackysoft.util.UserAllowedPredicate;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Service
@Transactional
public class DepartmentServiceImpl extends AbstractIdentifiedService<Department> implements
		DepartmentService {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5990035171808682875L;
	static final Log logger = LogFactory.getLog(DepartmentServiceImpl.class);
	private UserService userService;
    
    private static final Map<String,String> alias = Maps.newHashMap();
	public DepartmentServiceImpl() {
		this.type = Department.class;
		alias.put("一分厂", "一分厂");
		alias.put("三分厂", "三分厂");
		alias.put("五分厂", "五分厂");
		alias.put("冲压件厂", "冲压件厂");
		alias.put("冲压", "冲压件厂");
		alias.put("机械加工厂", "机械加工厂");
		alias.put("机加", "机械加工厂");
		alias.put("化工分厂", "化工分厂");
		alias.put("化工", "化工分厂");
		alias.put("庆华火工品研发分中心", "庆华火工品研发分中心");
		alias.put("火工品研发分中心", "庆华火工品研发分中心");
		alias.put("火工所", "庆华火工品研发分中心");
		alias.put("军用热电池研发中心", "军用热电池研发中心");
		alias.put("军用热电池中心", "军用热电池研发中心");
		alias.put("电池所", "军用热电池研发中心");
		alias.put("采购中心", "采购中心");
		alias.put("采购部", "采购中心");
		alias.put("采购", "采购中心");
		alias.put("塑业公司", "塑业公司");
		alias.put("塑料", "塑业公司");
		alias.put("塑业", "塑业公司");
	}

	@Override
	public void create(Department t) throws DataAccessException {
		Department topParent = parseTopParent(t);
		t.setTopParent(topParent);
		super.create(t);
	}

	/**
	 * 解析出所添加部门的顶级部门
	 * */
	private Department parseTopParent(Department t) throws DataAccessException {
		Department top = null;
		if(t.getParent()==null)return null;
		Department parent = get(t.getParent().getId()+"");
		while(parent!=null && parent.getParent()!=null){
			parent = parent.getParent();			
		}
		top = parent;
		return top;
		
	}

	/**
	 * 目前只能删除科室
	 * 递归删除所有科室
	 * */
	@Override
	public void remove(Department t) throws DataAccessException {
		String qs = "from "+this.table()+" d where d.parent=:p";
		Session sess = getSession();
		List list = sess.createQuery(qs).setParameter("p", t).list();
		if(list.size()==0){
			userService.reset(t);
			Department dt = get(t.getId());
			if(dt.getDepartmentType()==DepartmentType.Room){
				sess.delete(dt);
			}
		}else{
		    for(Object ot : list){
		    	Department dtp = (Department) ot;
		    	remove(dtp);
		    }
		}	
		
	}

	@Override
	public void update(Department t) throws DataAccessException {
		t.setTopParent(parseTopParent(t));
		super.update(t);
	}

	@Override
	public Collection<Department> gets() throws DataAccessException {
		List<Department> depts  =  getSession().createCriteria(type).list();
		Collections.sort(depts);
		return depts;
	}

	@Override
	public Collection<Department> searchs(Department parent)
			throws DataAccessException {
		Criteria crt = getSession().createCriteria(type);
		crt.add( Restrictions.eq("parent", parent));		
		return crt.list();
	}

	@Override
	public Collection<Department> getsByRoot()
			throws DataAccessException {
		Criteria crt = getSession().createCriteria(type);
		crt.add( Restrictions.isNull("parent"));	
		crt.addOrder(Property.forName("sort").asc());

		return crt.list();
	}



	@Override
	public void update(Department t, String... props)
			throws DataAccessException {
		Department dt = get(t.getId());
	    if(props!=null){
	    	for(String prop : props){
	    		Object value;
				try {
					value = PropertyUtils.getProperty(t, prop);
					PropertyUtils.setProperty(dt, prop, value);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}
	    		
	    	}
	        update(dt);
	    }
		
	}

	@Override
	public Collection<Department> getsByType(DepartmentType type)
			throws DataAccessException {
		String hql = String.format("from  %s  d where d.departmentType=:dtype order by d.sort desc",table());
		List list = getSession().createQuery(hql).setParameter("dtype", type).list();
		return list;
	}
	
	
	
	@Override
	public Collection<ZTreeNode> ztree(Department bean)
			throws DataAccessException {
		Collection<Department> depts = Lists.newArrayList();
		Collection<ZTreeNode> jsNodes = Lists.newArrayList();
		if(bean==null){
			bean = new Department();
			bean.setId("root");
		}
		
		if("root".equalsIgnoreCase(bean.getId())){
			depts = getsByRoot();
			jsNodes = (Collections2.transform(depts,new DepartmentZtreeFunction()));
			return jsNodes;
		}
		
		Department theDept = get(bean.getId());
		Collection<User> users = userService.gets(theDept);
		users  = Collections2.filter(users, new UserAllowedPredicate());
		depts = searchs(theDept);

		Collection<ZTreeNode> jsNode = Collections2.transform(depts,new DepartmentZtreeFunction());
		jsNodes.addAll(jsNode);
		jsNode = Collections2.transform(users, new UserZtreeFunction());
		jsNodes.addAll(jsNode);
		return jsNodes;
	}



	@Override
	public Collection<ZTreeNode> ztree(Department bean,
			Collection<DepartmentType> dtypes) throws DataAccessException {
		Collection<ZTreeNode> nodes = Lists.newArrayList();
		
		List<Department> list = null;
		if("root".equalsIgnoreCase(bean.getId())){
		    nodes.addAll(Collections2.transform(getsByRoot(),new DepartmentZtreeFunction()));
		    return nodes;
		}
		String hql = String.format("select new Department(d.id,d.name) from %s d where d.parent.id='%s'",table(), bean.getId());
		list = query(hql).list();
		nodes.addAll(Collections2.transform(list,new DepartmentZtreeFunction()));		
		return nodes;		
	}
	
	@Resource
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	
	
	@Override
	public Department getByName(String name) throws DataAccessException {
		String tname = alias.get(name);		
		if(tname==null) throw new IllegalArgumentException("错误的部门名称:"+name);
		String hql = HQL("from %s where name='%s'",table(),tname.trim());
		Iterator itr = query(hql).iterate();
		Department dept = (Department) (itr.hasNext()?itr.next():null);
		logger.info(dept);
		return dept;
	}
	
}
